package com.pisolution.actuator.client;

import com.pisolution.actuator.client.registration.ApplicationConfig;
import com.pisolution.actuator.client.registration.ApplicationFactory;
import com.pisolution.actuator.client.registration.ApplicationRegister;
import com.pisolution.actuator.client.registration.RegistrationListener;
import com.pisolution.actuator.client.registration.ServletApplicationFactory;

import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import javax.servlet.ServletContext;
import java.time.Duration;

/**
 * 监控中心自动接入工具 - 适用于独立客户端应用.
 *
 * @author sora
 * @version 0.1.0
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@Conditional(value = ActuatorClientEnabledCondition.class)
@AutoConfigureAfter(value = {
    RestTemplateAutoConfiguration.class,
    DispatcherServletAutoConfiguration.class
})
@EnableConfigurationProperties(value = {
    ActuatorClientConfig.class,
    ApplicationConfig.class,
    ServerProperties.class
})
public class ActuatorClientAutoConfiguration {
    // -------------------------------------------------------------------------------------------------
    //  注册相关
    // -------------------------------------------------------------------------------------------------

    /**
     * 如果注册事件监听器未创建 则创建该监听器.
     *
     * @param register 用于注册客户端应用.
     *
     * @return 缺失时的默认注册事件监听器.
     */
    @Bean
    @ConditionalOnMissingBean
    public RegistrationListener registrationListener(final ApplicationRegister register) {
        return new RegistrationListener(register);
    }

    /**
     * 如果应用信息获取工具尚未创建 则创建该工具.
     *
     * @param cfg 用于读取应用名称等信息.
     * @param srv 用于获取应用启动端口等信息.
     * @param ctx 获取上下文路径.
     *
     * @return 缺失时的默认应用信息获取工具.
     */
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Bean
    @Lazy(value = false)
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    @ConditionalOnMissingBean
    public ApplicationFactory applicationFactory(final ApplicationConfig cfg, final ServerProperties srv, final ServletContext ctx) {
        return new ServletApplicationFactory(cfg, srv, ctx);
    }

    /**
     * 如果注册工具尚未创建 则创建注册工具.
     *
     * @param cfg 用于获取请求发送工具配置.
     * @param factory 用于获取应用信息.
     *
     * @return 缺失时默认的注册工具.
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnBean(value = RestTemplateBuilder.class)
    public ApplicationRegister applicationRegister(final ActuatorClientConfig cfg, final ApplicationFactory factory) {
        RestTemplateBuilder builder = new RestTemplateBuilder()
            .setConnectTimeout(Duration.ofMillis(cfg.getConnectTimeout()))
            .setReadTimeout(Duration.ofMillis(cfg.getReadTimeout()));

        if (!StringUtils.isAnyBlank(cfg.getUsername(), cfg.getPassword())) {
            builder = builder.basicAuthentication(cfg.getUsername(), cfg.getPassword());
        }

        return new ApplicationRegister(cfg, builder.build(), factory);
    }
}
